﻿using System;
using System.Collections.Generic;
using System.Linq;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
using YArchitech.Revit;
using YJKArch.Utils;
using TopologySearch;

namespace RegionSplittor.Utils.InternalCorner
{
	public class CurveUtils
	{
		public static XYZ GetMaxDistancePt(Curve curve, XYZ ptCmp)
		{
			XYZ hyendPoint = curve.GetEndPoint(0);
			XYZ xyz = new XYZ(hyendPoint.X, hyendPoint.Y, 0.0);
			XYZ hyendPoint2 = curve.GetEndPoint(1);
			XYZ xyz2 = new XYZ(hyendPoint2.X, hyendPoint2.Y, 0.0);
			XYZ xyz3 = new XYZ(ptCmp.X, ptCmp.Y, 0.0);
			double num = xyz3.DistanceTo(xyz);
			double num2 = xyz3.DistanceTo(xyz2);
			XYZ result;
			if (num > num2)
			{
				result = hyendPoint;
			}
			else
			{
				result = hyendPoint2;
			}
			return result;
		}

		public static XYZ GetMinDistancePt(Curve curve, XYZ ptCmp)
		{
			XYZ hyendPoint = curve.GetEndPoint(0);
			XYZ xyz = new XYZ(hyendPoint.X, hyendPoint.Y, 0.0);
			XYZ hyendPoint2 = curve.GetEndPoint(1);
			XYZ xyz2 = new XYZ(hyendPoint2.X, hyendPoint2.Y, 0.0);
			XYZ xyz3 = new XYZ(ptCmp.X, ptCmp.Y, 0.0);
			double num = xyz3.DistanceTo(xyz);
			double num2 = xyz3.DistanceTo(xyz2);
			XYZ result;
			if (num > num2)
			{
				result = hyendPoint2;
			}
			else
			{
				result = hyendPoint;
			}
			return result;
		}

		public static List<XYZ> GetClosedRegionPts(List<Curve> lstCurve)
		{
			List<XYZ> list = new List<XYZ>();
			foreach (Curve curve in lstCurve)
			{
				if (curve is Line)
				{
					list.Add(curve.GetEndPoint(0));
					list.Add(curve.GetEndPoint(1));
				}
				else if (curve is Arc)
				{
					list.AddRange(curve.Tessellate());
				}
			}
			list = list.Distinct<XYZ>().ToList<XYZ>();
			return list;
		}

		public static List<XYZ> GetGroupIntersectPoints(List<Curve> lstCurve, Curve curve)
		{
			List<XYZ> list = new List<XYZ>();
			foreach (Curve curveS in lstCurve)
			{
				XYZ curveIntersectPt = CurveUtils.GetCurveIntersectPt(curve, curveS);
				if (curveIntersectPt != null)
				{
					list.Add(curveIntersectPt);
				}
			}
			return list;
		}

		public static List<Curve> GetAntiClockWiseCurve(List<Curve> lstCurve, ExternalCommandData cmdData)
		{
			List<Pole2D> poleList = CurveUtils.LstCurveToPole2D(lstCurve);
			return new StructureLoopSearcher(cmdData).GetFullFloorEdgeLoops(poleList, StructureLoopSearcher.SearchEdgeLocation.SEL_Outside).First<List<Curve>>();
		}

		public static Curve GetExtensionLine(XYZ ptStart, XYZ vecDir)
		{
			return Line.CreateUnbound(ptStart, vecDir);
		}

		public static XYZ GetCurveIntersectPt(Curve curveF, Curve curveS)
		{
			XYZ result = null;
			IntersectionResultArray intersectionResultArray = null;
			curveF.Intersect(curveS, out intersectionResultArray);
			if (intersectionResultArray != null && 1 == intersectionResultArray.Size)
			{
				result = intersectionResultArray.get_Item(0).XYZPoint;
			}
			return result;
		}

		public static XYZ GetNearExtensionLineIntersectPt(InternalCornerData data, Curve extensionCurve, List<Curve> lstCurve)
		{
			XYZ result = null;
			double num = double.MaxValue;
			XYZ intersectPt = data.m_intersectPt;
			XYZ ptMaxEnd = data.m_ptMaxEnd;
			XYZ ptMinEnd = data.m_ptMinEnd;
			foreach (Curve curve in lstCurve)
			{
				IntersectionResultArray intersectionResultArray = null;
				extensionCurve.Intersect(curve, out intersectionResultArray);
				if (intersectionResultArray != null && intersectionResultArray.Size == 1)
				{
					XYZ xyzpoint = intersectionResultArray.get_Item(0).XYZPoint;
					double eps = 1E-09;
					bool flag = Geometry.IsEqual(xyzpoint, intersectPt, eps);
					bool flag2 = Geometry.IsEqual(xyzpoint, ptMaxEnd, eps);
					bool flag3 = Geometry.IsEqual(xyzpoint, ptMinEnd, eps);
					if (!flag && !flag2 && !flag3)
					{
						double num2 = xyzpoint.DistanceTo(intersectPt);
						if (num2 < num)
						{
							result = xyzpoint;
							num = num2;
						}
					}
				}
			}
			return result;
		}

		public static Curve GetMidUnboundCurve(Curve curve)
		{
			XYZ hyendPoint = curve.GetEndPoint(0);
			XYZ xyz = new XYZ(hyendPoint.X, hyendPoint.Y, 0.0);
			XYZ hyendPoint2 = curve.GetEndPoint(1);
			XYZ xyz2 = new XYZ(hyendPoint2.X, hyendPoint2.Y, 0.0);
			XYZ xyz3 = Geometry.CalculatMidPoint(xyz, xyz2);
			XYZ xyz4 = (xyz2 - xyz).Normalize();
			return Line.CreateUnbound(xyz3, xyz4);
		}

		public static List<Curve> MergeCurves(List<Curve> lstCurve)
		{
			if (lstCurve.Count < 2)
			{
				return lstCurve;
			}
			Curve curve = lstCurve[0];
			List<Curve> list = new List<Curve>();
			for (int i = 1; i < lstCurve.Count; i++)
			{
				Curve curve2 = CurveUtils.Merge2Curve(curve, lstCurve[i]);
				if (null == curve2)
				{
					list.Add(curve);
					curve = lstCurve[i];
				}
				else
				{
					curve = curve2;
				}
			}
			Curve curve3 = CurveUtils.Merge2Curve(curve, list[0]);
			if (null == curve3)
			{
				list.Add(curve);
			}
			else
			{
				list.RemoveAt(0);
				list.Add(curve3);
			}
			return list;
		}

		public static Curve Merge2Curve(Curve curveF, Curve curveS)
		{
			Line line = curveF as Line;
			Line line2 = curveS as Line;
			Arc arc = curveF as Arc;
			Arc arc2 = curveS as Arc;
			if (null != line && null != line2)
			{
				if (Geometry.IsParallel(line.Direction, line2.Direction))
				{
					XYZ hyendPoint = line.GetEndPoint(0);
					XYZ hyendPoint2 = line.GetEndPoint(1);
					XYZ hyendPoint3 = line2.GetEndPoint(0);
					XYZ hyendPoint4 = line2.GetEndPoint(1);
					if (hyendPoint.DistanceTo(hyendPoint3) < CurveUtils.m_dTol || hyendPoint.DistanceTo(hyendPoint4) < CurveUtils.m_dTol || hyendPoint2.DistanceTo(hyendPoint3) < CurveUtils.m_dTol || hyendPoint2.DistanceTo(hyendPoint4) < CurveUtils.m_dTol)
					{
						List<XYZ> maxDistTwoPoints = PointUtils.GetMaxDistTwoPoints(new List<XYZ>
						{
							hyendPoint,
							hyendPoint2,
							hyendPoint3,
							hyendPoint4
						});
						if (maxDistTwoPoints != null)
						{
							return Line.CreateBound(maxDistTwoPoints.First<XYZ>(), maxDistTwoPoints.Last<XYZ>());
						}
					}
				}
			}
			else if (null != arc && null != arc2)
			{
				double radius = arc.Radius;
				double radius2 = arc2.Radius;
				XYZ center = arc.Center;
				XYZ center2 = arc2.Center;
				if (Math.Abs(radius - radius2) < CurveUtils.m_dTol && center.DistanceTo(center2) < CurveUtils.m_dTol)
				{
					XYZ hyendPoint5 = arc.GetEndPoint(0);
					XYZ hyendPoint6 = arc.GetEndPoint(1);
					XYZ hyendPoint7 = arc2.GetEndPoint(0);
					XYZ hyendPoint8 = arc2.GetEndPoint(1);
					if (hyendPoint5.DistanceTo(hyendPoint7) < CurveUtils.m_dTol || hyendPoint5.DistanceTo(hyendPoint8) < CurveUtils.m_dTol || hyendPoint6.DistanceTo(hyendPoint7) < CurveUtils.m_dTol || hyendPoint6.DistanceTo(hyendPoint8) < CurveUtils.m_dTol)
					{
						XYZ xyz = null;
						XYZ xyz2 = null;
						XYZ xyz3 = null;
						if (hyendPoint5.DistanceTo(hyendPoint7) < CurveUtils.m_dTol)
						{
							xyz = hyendPoint6;
							xyz2 = hyendPoint8;
							xyz3 = hyendPoint5;
						}
						else if (hyendPoint5.DistanceTo(hyendPoint8) < CurveUtils.m_dTol)
						{
							xyz = hyendPoint6;
							xyz2 = hyendPoint7;
							xyz3 = hyendPoint5;
						}
						else if (hyendPoint6.DistanceTo(hyendPoint7) < CurveUtils.m_dTol)
						{
							xyz = hyendPoint5;
							xyz2 = hyendPoint8;
							xyz3 = hyendPoint6;
						}
						else if (hyendPoint6.DistanceTo(hyendPoint8) < CurveUtils.m_dTol)
						{
							xyz = hyendPoint5;
							xyz2 = hyendPoint7;
							xyz3 = hyendPoint6;
						}
						Curve result = null;
						if (xyz != null && xyz2 != null && xyz3 != null)
						{
							result = Arc.Create(xyz, xyz2, xyz3);
						}
						return result;
					}
				}
			}
			return null;
		}

		public static XYZ GetGroupMaxDistPoint(List<Curve> lstCurve, XYZ ptCmp)
		{
			return PointUtils.GetMaxDistToPoint(CurveUtils.GetClosedRegionPts(lstCurve), ptCmp);
		}

		public static List<Curve> GetTwoCurveByCurve(Curve curve)
		{
			List<Curve> list = new List<Curve>();
			if (curve is Line)
			{
				Line line = curve as Line;
				XYZ hyendPoint = line.GetEndPoint(0);
				XYZ hyendPoint2 = line.GetEndPoint(1);
				XYZ xyz = Geometry.CalculatMidPoint(line);
				list.Add(Line.CreateBound(hyendPoint, xyz));
				list.Add(Line.CreateBound(xyz, hyendPoint2));
			}
			else
			{
				Arc arc = curve as Arc;
			}
			return list;
		}

		public static List<XYZ> GetGroupMidPoints(List<Curve> lstCurve)
		{
			List<XYZ> list = new List<XYZ>();
			foreach (Curve curve in lstCurve)
			{
				XYZ xyz = null;
				if (curve is Line)
				{
					xyz = Geometry.CalculatMidPoint(curve as Line);
				}
				else if (curve is Arc)
				{
					xyz = Geometry.CalculatMidPoint(curve as Arc);
				}
				if (xyz != null)
				{
					list.Add(xyz);
				}
			}
			return list;
		}

		public static List<Curve> GetOneGroupCircle(List<Curve> lstCurve, double dR)
		{
			List<Curve> list = new List<Curve>();
			foreach (Curve curve in lstCurve)
			{
				XYZ xyz = null;
				if (curve is Line)
				{
					xyz = Geometry.CalculatMidPoint(curve as Line);
				}
				else if (curve is Arc)
				{
					xyz = Geometry.CalculatMidPoint(curve as Arc);
				}
				if (xyz != null)
				{
					double num = 0.0;
					double num2 = Math.PI*2;
					XYZ basisX = XYZ.BasisX;
					XYZ basisY = XYZ.BasisY;
					Arc arc = Arc.Create(xyz, dR, num, num2, basisX, basisY);
					if (null != arc)
					{
						list.Add(arc);
					}
				}
			}
			return list;
		}

		public static List<Curve> GetCurveNEqualSplitCurves(Curve curve, int nNEqualSplit)
		{
			List<Curve> list = new List<Curve>();
			if (nNEqualSplit < 2)
			{
				return list;
			}
			if (curve is Line)
			{
				List<XYZ> list2 = new List<XYZ>();
				Line curve2 = curve as Line;
				XYZ hyendPoint = curve2.GetEndPoint(0);
				XYZ hyendPoint2 = curve2.GetEndPoint(1);
				list2.Add(hyendPoint);
				for (int i = 1; i < nNEqualSplit; i++)
				{
					int num = nNEqualSplit - i;
					double num2 = ((double)num * hyendPoint.X + (double)i * hyendPoint2.X) / (double)nNEqualSplit;
					double num3 = ((double)num * hyendPoint.Y + (double)i * hyendPoint2.Y) / (double)nNEqualSplit;
					list2.Add(new XYZ(num2, num3, 0.0));
				}
				list2.Add(hyendPoint2);
				if (list2.Count > 1)
				{
					for (int j = 0; j < list2.Count - 1; j++)
					{
						list.Add(Line.CreateBound(list2[j], list2[j + 1]));
					}
				}
			}
			else if (curve is Arc)
			{
				list = CurveUtils.GetArcNEqualSplitCurves(curve, nNEqualSplit);
			}
			return list;
		}

		public static List<Curve> GetArcNEqualSplitCurves(Curve curve, int nNEqualSplit)
		{
			List<Curve> list = new List<Curve>();
			if (nNEqualSplit < 2 || !(curve is Arc))
			{
				return list;
			}
			Arc arc = curve as Arc;
			XYZ hyendPoint = arc.GetEndPoint(0);
			XYZ hyendPoint2 = arc.GetEndPoint(1);
			XYZ center = arc.Center;
			double radius = arc.Radius;
			double num;
			if (Geometry.Greaterthan_Or_Equal(hyendPoint.Y, center.Y))
			{
				num = Math.Acos((hyendPoint.X - center.X) / radius);
			}
			else
			{
				num = Math.PI*2 - Math.Acos((hyendPoint.X - center.X) / radius);
			}
			double num2;
			if (Geometry.Greaterthan_Or_Equal(hyendPoint2.Y, center.Y))
			{
				num2 = Math.Acos((hyendPoint2.X - center.X) / radius);
			}
			else
			{
				num2 = Math.PI*2 - Math.Acos((hyendPoint2.X - center.X) / radius);
			}
			double num3 = (num2 - num) / (double)nNEqualSplit;
			double num4 = hyendPoint.X;
			double num5 = hyendPoint.Y;
			double x = center.X;
			double y = center.Y;
			for (int i = 1; i < nNEqualSplit; i++)
			{
				double num6 = (num4 - x) * Math.Cos(num3) - (num5 - y) * Math.Sin(num3) + x;
				double num7 = (num4 - x) * Math.Sin(num3) + (num5 - y) * Math.Cos(num3) + y;
				XYZ xyz = new XYZ(num6, num7, 0.0);
				XYZ xyz2 = new XYZ(num4, num5, 0.0);
				XYZ xyz3 = Geometry.CalculatMidPoint(xyz2, xyz, center, arc.Normal);
				list.Add(Arc.Create(xyz2, xyz, xyz3));
				num4 = num6;
				num5 = num7;
			}
			return list;
		}

		public static List<Curve> GetCurveNEqualSplitByEvaluate(Curve curve, int nNEqualSplit)
		{
			List<Curve> list = new List<Curve>();
			if (2 > nNEqualSplit)
			{
				return list;
			}
			double length = curve.Length;
			double num = 1.0 / (double)nNEqualSplit;
			XYZ hyendPoint = curve.GetEndPoint(0);
			XYZ hyendPoint2 = curve.GetEndPoint(1);
			XYZ xyz = hyendPoint;
			bool flag = false;
			if (curve is Arc)
			{
				flag = true;
			}
			for (int i = 1; i < nNEqualSplit; i++)
			{
				XYZ xyz2 = curve.Evaluate(num * (double)i, false);
				if (flag)
				{
					Arc arc = curve as Arc;
					XYZ xyz3 = Geometry.CalculatMidPoint(xyz, xyz2, arc.Center, arc.Normal);
					list.Add(Arc.Create(xyz, xyz2, xyz3));
					xyz = xyz2;
					if (i == nNEqualSplit - 1)
					{
						XYZ xyz4 = Geometry.CalculatMidPoint(xyz, hyendPoint2, arc.Center, arc.Normal);
						list.Add(Arc.Create(xyz, hyendPoint2, xyz4));
					}
				}
				else
				{
					list.Add(Line.CreateBound(xyz, xyz2));
					xyz = xyz2;
					if (i == nNEqualSplit - 1)
					{
						list.Add(Line.CreateBound(xyz, hyendPoint2));
					}
				}
			}
			return list;
		}

		public static List<Pole2D> LstCurveToPole2D(List<Curve> lstCurve)
		{
			List<Pole2D> list = new List<Pole2D>();
			foreach (Curve curve in lstCurve)
			{
				if (curve is Line)
				{
					XYZ hyendPoint = curve.GetEndPoint(0);
					XYZ hyendPoint2 = curve.GetEndPoint(1);
					list.Add(Pole2D.NewStructure2DPole(ElementId.InvalidElementId, hyendPoint, hyendPoint2, 0.0, 0.0));
				}
				else if (curve is Arc)
				{
					Arc arc = curve as Arc;
					if (!(null == arc))
					{
						XYZ hyendPoint3 = curve.GetEndPoint(0);
						XYZ hyendPoint4 = curve.GetEndPoint(1);
						list.Add(Pole2D.NewStructure2DPole(ElementId.InvalidElementId, hyendPoint3, hyendPoint4, arc.Center, arc.Normal, 0.0, 0.0));
					}
				}
			}
			return list;
		}

		public static CurveArray LstCurveToCurveArray(List<Curve> lstCurve)
		{
			CurveArray curveArray = new CurveArray();
			foreach (Curve curve in lstCurve)
			{
				if (null != curve)
				{
					curveArray.Append(curve);
				}
			}
			return curveArray;
		}

		public static CurveLoop LstCurveToCurveLoop(List<Curve> lstCurve)
		{
			CurveLoop result = null;
			try
			{
				result = CurveLoop.Create(lstCurve);
			}
			catch (Exception)
			{
			}
			return result;
		}

		public static CurveArray CurveLoopToCurveArray(CurveLoop loop)
		{
			return CurveUtils.LstCurveToCurveArray(CurveUtils.CurveLoopToLstCurve(loop));
		}

		public static List<Curve> CurveLoopToLstCurve(CurveLoop loop)
		{
			List<Curve> list = new List<Curve>();
			CurveLoopIterator curveLoopIterator = loop.GetCurveLoopIterator();
			while (curveLoopIterator.MoveNext())
			{
				Curve item = curveLoopIterator.Current;
				list.Add(item);
			}
			return list;
		}

		public static bool CreateConvexhullLoop(CurveLoop loop, out CurveLoop outLoop)
		{
			bool result = false;
			outLoop = null;
			List<XYZ> list = new List<XYZ>();
			CurveLoopIterator curveLoopIterator = loop.GetCurveLoopIterator();
			while (curveLoopIterator.MoveNext())
			{
				Curve curve = curveLoopIterator.Current;
				if (curve is Line)
				{
					XYZ hyendPoint = curve.GetEndPoint(0);
					XYZ hyendPoint2 = curve.GetEndPoint(1);
					list.Add(hyendPoint);
					list.Add(hyendPoint2);
				}
				else if (curve is Arc)
				{
					list.AddRange(curve.Tessellate());
				}
			}
			List<XYZ> list2 = ConvexHull.Convert2ConvexHull(list);
			if (list2.Count > 2)
			{
				List<Curve> list3 = new List<Curve>();
				int count = list2.Count;
				for (int i = 0; i < list2.Count; i++)
				{
					XYZ xyz;
					XYZ xyz2;
					if (i == count - 1)
					{
						xyz = list2[count - 1];
						xyz2 = list2[0];
					}
					else
					{
						xyz = list2[i];
						xyz2 = list2[i + 1];
					}
					Curve curve2 = Line.CreateBound(xyz, xyz2);
					if (null != curve2)
					{
						list3.Add(curve2);
					}
				}
				if (list3.Count > 2)
				{
					outLoop = CurveLoop.Create(list3);
					result = true;
				}
			}
			return result;
		}

		private static double m_dTol = 1E-09;
	}
}
